// Created on 15.07.2005 at 13:35
// Created by Mikhail Sokolov (mikhail.sokolov@smekalka.ru)
// Copyright (C) 2005 Smekalka! (http://smekalka.net)
// All rights reserved.

using System;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Security.Cryptography;
using System.Windows.Forms;

namespace FileHashCodeCalculator
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class MainForm : System.Windows.Forms.Form
	{
		private Hashtable hashAlgorithms = new Hashtable(5);
		private HashAlgorithm currentHashAlgorithm;
		private HashCode hashCode = HashCode.Empty;

		private System.Windows.Forms.OpenFileDialog openFileDialog;
		private System.Windows.Forms.TextBox tbxHashCode;
		private System.Windows.Forms.TextBox tbxFilePath;
		private System.Windows.Forms.Label lbFilePath;
		private System.Windows.Forms.Label lbHashCode;
		private System.Windows.Forms.Button btBrowseForFile;
		private System.Windows.Forms.Button btCalculate;
		private System.Windows.Forms.ToolTip toolTip;
		private System.Windows.Forms.CheckBox cbxUseSeparator;
		private System.Windows.Forms.ErrorProvider errorProvider;
		private System.Windows.Forms.GroupBox gbxAlgorithm;
		private System.Windows.Forms.RadioButton rbMD5;
		private System.Windows.Forms.RadioButton rbSHA1;
		private System.Windows.Forms.RadioButton rbSHA256;
		private System.Windows.Forms.RadioButton rbSHA384;
		private System.Windows.Forms.RadioButton rbSHA512;
		private System.Windows.Forms.Button btCopy;
		private System.ComponentModel.IContainer components;

		public MainForm()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (components != null) 
				{
					components.Dispose();
				}

				foreach (IDisposable hashAlgorithm in hashAlgorithms.Values) hashAlgorithm.Dispose();
			}
			base.Dispose(disposing);
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MainForm));
			this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
			this.tbxFilePath = new System.Windows.Forms.TextBox();
			this.tbxHashCode = new System.Windows.Forms.TextBox();
			this.lbFilePath = new System.Windows.Forms.Label();
			this.lbHashCode = new System.Windows.Forms.Label();
			this.btBrowseForFile = new System.Windows.Forms.Button();
			this.btCalculate = new System.Windows.Forms.Button();
			this.toolTip = new System.Windows.Forms.ToolTip(this.components);
			this.rbMD5 = new System.Windows.Forms.RadioButton();
			this.rbSHA1 = new System.Windows.Forms.RadioButton();
			this.rbSHA256 = new System.Windows.Forms.RadioButton();
			this.rbSHA384 = new System.Windows.Forms.RadioButton();
			this.rbSHA512 = new System.Windows.Forms.RadioButton();
			this.btCopy = new System.Windows.Forms.Button();
			this.cbxUseSeparator = new System.Windows.Forms.CheckBox();
			this.errorProvider = new System.Windows.Forms.ErrorProvider();
			this.gbxAlgorithm = new System.Windows.Forms.GroupBox();
			this.gbxAlgorithm.SuspendLayout();
			this.SuspendLayout();
			// 
			// openFileDialog
			// 
			this.openFileDialog.Filter = "All files|*.*";
			// 
			// tbxFilePath
			// 
			this.tbxFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.tbxFilePath.Location = new System.Drawing.Point(16, 32);
			this.tbxFilePath.Name = "tbxFilePath";
			this.tbxFilePath.Size = new System.Drawing.Size(312, 20);
			this.tbxFilePath.TabIndex = 1;
			this.tbxFilePath.Text = "";
			this.tbxFilePath.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			this.tbxFilePath.TextChanged += new System.EventHandler(this.tbxFilePath_TextChanged);
			this.tbxFilePath.Enter += new System.EventHandler(this.tbxFilePath_Enter);
			// 
			// tbxHashCode
			// 
			this.tbxHashCode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.tbxHashCode.Location = new System.Drawing.Point(16, 240);
			this.tbxHashCode.Multiline = true;
			this.tbxHashCode.Name = "tbxHashCode";
			this.tbxHashCode.ReadOnly = true;
			this.tbxHashCode.Size = new System.Drawing.Size(344, 72);
			this.tbxHashCode.TabIndex = 5;
			this.tbxHashCode.Text = "";
			this.toolTip.SetToolTip(this.tbxHashCode, "Here is the hash code computed for the specified file");
			this.tbxHashCode.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			// 
			// lbFilePath
			// 
			this.lbFilePath.Location = new System.Drawing.Point(16, 16);
			this.lbFilePath.Name = "lbFilePath";
			this.lbFilePath.Size = new System.Drawing.Size(64, 16);
			this.lbFilePath.TabIndex = 0;
			this.lbFilePath.Text = "File path:";
			// 
			// lbHashCode
			// 
			this.lbHashCode.Location = new System.Drawing.Point(16, 224);
			this.lbHashCode.Name = "lbHashCode";
			this.lbHashCode.Size = new System.Drawing.Size(64, 16);
			this.lbHashCode.TabIndex = 4;
			this.lbHashCode.Text = "Hash code:";
			// 
			// btBrowseForFile
			// 
			this.btBrowseForFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btBrowseForFile.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
			this.btBrowseForFile.Image = ((System.Drawing.Image)(resources.GetObject("btBrowseForFile.Image")));
			this.btBrowseForFile.Location = new System.Drawing.Point(336, 30);
			this.btBrowseForFile.Name = "btBrowseForFile";
			this.btBrowseForFile.Size = new System.Drawing.Size(24, 24);
			this.btBrowseForFile.TabIndex = 2;
			this.toolTip.SetToolTip(this.btBrowseForFile, "Browse for file");
			this.btBrowseForFile.Click += new System.EventHandler(this.btBrowseForFile_Click);
			this.btBrowseForFile.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			// 
			// btCalculate
			// 
			this.btCalculate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btCalculate.Enabled = false;
			this.btCalculate.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
			this.btCalculate.Image = ((System.Drawing.Image)(resources.GetObject("btCalculate.Image")));
			this.btCalculate.Location = new System.Drawing.Point(304, 320);
			this.btCalculate.Name = "btCalculate";
			this.btCalculate.Size = new System.Drawing.Size(24, 24);
			this.btCalculate.TabIndex = 7;
			this.toolTip.SetToolTip(this.btCalculate, "Calculate hash code");
			this.btCalculate.Click += new System.EventHandler(this.btCalculate_Click);
			this.btCalculate.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			// 
			// rbMD5
			// 
			this.rbMD5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.rbMD5.Checked = true;
			this.rbMD5.Location = new System.Drawing.Point(8, 24);
			this.rbMD5.Name = "rbMD5";
			this.rbMD5.Size = new System.Drawing.Size(320, 24);
			this.rbMD5.TabIndex = 0;
			this.rbMD5.TabStop = true;
			this.rbMD5.Tag = "MD5";
			this.rbMD5.Text = "MD5 (16 bytes)";
			this.toolTip.SetToolTip(this.rbMD5, "MD5 hash algorithm (16 bytes code)");
			this.rbMD5.CheckedChanged += new System.EventHandler(this.algorithmRadioButton_CheckedChanged);
			// 
			// rbSHA1
			// 
			this.rbSHA1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.rbSHA1.Location = new System.Drawing.Point(8, 48);
			this.rbSHA1.Name = "rbSHA1";
			this.rbSHA1.Size = new System.Drawing.Size(320, 24);
			this.rbSHA1.TabIndex = 1;
			this.rbSHA1.Tag = "SHA1";
			this.rbSHA1.Text = "SHA1 (24 bytes)";
			this.toolTip.SetToolTip(this.rbSHA1, "SHA1 hash algorithm (24 bytes code)");
			this.rbSHA1.CheckedChanged += new System.EventHandler(this.algorithmRadioButton_CheckedChanged);
			// 
			// rbSHA256
			// 
			this.rbSHA256.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.rbSHA256.Location = new System.Drawing.Point(8, 72);
			this.rbSHA256.Name = "rbSHA256";
			this.rbSHA256.Size = new System.Drawing.Size(320, 24);
			this.rbSHA256.TabIndex = 2;
			this.rbSHA256.Tag = "SHA256";
			this.rbSHA256.Text = "SHA256 (32 bytes)";
			this.toolTip.SetToolTip(this.rbSHA256, "SHA256 hash algorithm (32 bytes code)");
			this.rbSHA256.CheckedChanged += new System.EventHandler(this.algorithmRadioButton_CheckedChanged);
			// 
			// rbSHA384
			// 
			this.rbSHA384.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.rbSHA384.Location = new System.Drawing.Point(8, 96);
			this.rbSHA384.Name = "rbSHA384";
			this.rbSHA384.Size = new System.Drawing.Size(320, 24);
			this.rbSHA384.TabIndex = 3;
			this.rbSHA384.Tag = "SHA384";
			this.rbSHA384.Text = "SHA384 (48 bytes)";
			this.toolTip.SetToolTip(this.rbSHA384, "SHA384 hash algorithm (48 bytes code)");
			this.rbSHA384.CheckedChanged += new System.EventHandler(this.algorithmRadioButton_CheckedChanged);
			// 
			// rbSHA512
			// 
			this.rbSHA512.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.rbSHA512.Location = new System.Drawing.Point(8, 120);
			this.rbSHA512.Name = "rbSHA512";
			this.rbSHA512.Size = new System.Drawing.Size(320, 24);
			this.rbSHA512.TabIndex = 4;
			this.rbSHA512.Tag = "SHA512";
			this.rbSHA512.Text = "SHA512 (64 bytes)";
			this.toolTip.SetToolTip(this.rbSHA512, "SHA512 hash algorithm (64 bytes code)");
			this.rbSHA512.CheckedChanged += new System.EventHandler(this.algorithmRadioButton_CheckedChanged);
			// 
			// btCopy
			// 
			this.btCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btCopy.Enabled = false;
			this.btCopy.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
			this.btCopy.Image = ((System.Drawing.Image)(resources.GetObject("btCopy.Image")));
			this.btCopy.Location = new System.Drawing.Point(336, 320);
			this.btCopy.Name = "btCopy";
			this.btCopy.Size = new System.Drawing.Size(24, 24);
			this.btCopy.TabIndex = 8;
			this.toolTip.SetToolTip(this.btCopy, "Copy calculated hash code to the clipboard");
			this.btCopy.Click += new System.EventHandler(this.btCopy_Click);
			// 
			// cbxUseSeparator
			// 
			this.cbxUseSeparator.Location = new System.Drawing.Point(16, 320);
			this.cbxUseSeparator.Name = "cbxUseSeparator";
			this.cbxUseSeparator.Size = new System.Drawing.Size(96, 16);
			this.cbxUseSeparator.TabIndex = 6;
			this.cbxUseSeparator.Text = "Use separator";
			this.cbxUseSeparator.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			this.cbxUseSeparator.CheckedChanged += new System.EventHandler(this.cbxUseSeparator_CheckedChanged);
			// 
			// errorProvider
			// 
			this.errorProvider.ContainerControl = this;
			// 
			// gbxAlgorithm
			// 
			this.gbxAlgorithm.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.gbxAlgorithm.Controls.Add(this.rbMD5);
			this.gbxAlgorithm.Controls.Add(this.rbSHA1);
			this.gbxAlgorithm.Controls.Add(this.rbSHA256);
			this.gbxAlgorithm.Controls.Add(this.rbSHA384);
			this.gbxAlgorithm.Controls.Add(this.rbSHA512);
			this.gbxAlgorithm.Location = new System.Drawing.Point(16, 64);
			this.gbxAlgorithm.Name = "gbxAlgorithm";
			this.gbxAlgorithm.Size = new System.Drawing.Size(344, 152);
			this.gbxAlgorithm.TabIndex = 3;
			this.gbxAlgorithm.TabStop = false;
			this.gbxAlgorithm.Text = "Algorithm";
			// 
			// MainForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(374, 360);
			this.Controls.Add(this.gbxAlgorithm);
			this.Controls.Add(this.cbxUseSeparator);
			this.Controls.Add(this.tbxHashCode);
			this.Controls.Add(this.tbxFilePath);
			this.Controls.Add(this.btBrowseForFile);
			this.Controls.Add(this.lbFilePath);
			this.Controls.Add(this.lbHashCode);
			this.Controls.Add(this.btCalculate);
			this.Controls.Add(this.btCopy);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
			this.MaximizeBox = false;
			this.Name = "MainForm";
			this.Text = "File Hash Code Calculator";
			this.TopMost = true;
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);
			this.Load += new System.EventHandler(this.MainForm_Load);
			this.Activated += new System.EventHandler(this.MainForm_Activated);
			this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
			this.gbxAlgorithm.ResumeLayout(false);
			this.ResumeLayout(false);

		}
		#endregion

		public void SwitchHashAlgorithm(string algorithmName)
		{
			lock (this)
			{
				if (hashAlgorithms.ContainsKey(algorithmName)) this.currentHashAlgorithm = (HashAlgorithm) hashAlgorithms[algorithmName];
				else
				{
					this.currentHashAlgorithm = HashAlgorithm.Create(algorithmName);
					hashAlgorithms.Add(algorithmName, this.currentHashAlgorithm);
				}
			}
			Calculate();
		}
		
		public void Calculate()
		{
			if (tbxFilePath.Text == String.Empty) return;

			this.Cursor = Cursors.WaitCursor;

			try
			{
				using (FileStream fileStream = new FileStream(tbxFilePath.Text, FileMode.Open, FileAccess.Read, FileShare.None))
				{
					hashCode = currentHashAlgorithm.ComputeHash(fileStream);
					fileStream.Close();
				}
			}
			catch (IOException e)
			{
				errorProvider.SetIconAlignment(tbxFilePath, ErrorIconAlignment.MiddleLeft);
				errorProvider.SetError(tbxFilePath, e.Message);
				MessageBox.Show(this, e.Message, "An error occured", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			catch (Exception e)
			{
				MessageBox.Show(this, e.Message, "An error occured", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				tbxHashCode.Text = String.Empty;
				this.Cursor = Cursors.Default;
			}

			if (hashCode != HashCode.Empty) tbxHashCode.Text = (cbxUseSeparator.Checked ? hashCode.ToString("D") : hashCode.ToString("N"));
			btCopy.Enabled = true;
		}
	
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new MainForm());
		}

		private void MainForm_Load(object sender, System.EventArgs e)
		{
			SwitchHashAlgorithm("MD5");
		}

		private void MainForm_Activated(object sender, System.EventArgs e)
		{
			Opacity = 1.0;
			Refresh();
		}

		private void MainForm_Deactivate(object sender, System.EventArgs e)
		{
			Opacity = 0.9;
			Refresh();
		}

		private void MainForm_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if (e.KeyCode == Keys.F5) Calculate();
		}

		private void btBrowseForFile_Click(object sender, System.EventArgs e)
		{
			openFileDialog.FileName = tbxFilePath.Text;
			if (openFileDialog.ShowDialog() == DialogResult.OK) tbxFilePath.Text = openFileDialog.FileName;
			Calculate();
		}

		private void tbxFilePath_TextChanged(object sender, System.EventArgs e)
		{
			btCalculate.Enabled = (tbxFilePath.Text != String.Empty);
			errorProvider.SetError(tbxFilePath, String.Empty);
		}

		private void tbxFilePath_Enter(object sender, System.EventArgs e)
		{
			tbxFilePath.SelectionStart = 0;
			tbxFilePath.SelectionLength = tbxFilePath.Text.Length;
		}

		private void btCalculate_Click(object sender, System.EventArgs e)
		{
			BeginInvoke(new System.Threading.ThreadStart(Calculate));
		}

		private void algorithmRadioButton_CheckedChanged(object sender, System.EventArgs e)
		{
			if (((RadioButton) sender).Checked)	SwitchHashAlgorithm((string) ((Control) sender).Tag);
		}

		private void cbxUseSeparator_CheckedChanged(object sender, System.EventArgs e)
		{
			if (hashCode != HashCode.Empty) tbxHashCode.Text = (cbxUseSeparator.Checked ? hashCode.ToString("D") : hashCode.ToString("N"));
		}

		private void btCopy_Click(object sender, System.EventArgs e)
		{
			Clipboard.SetDataObject(tbxHashCode.Text, true);
		}
	}
}
